package com.example.testall;


import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;

import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;


@Slf4j
public class HttpRequestUtils {


    private static PoolingHttpClientConnectionManager connMgr;
    private static RequestConfig requestConfig;
    private static final int MAX_TIMEOUT = 7000;

    static {
        // 设置连接池
        connMgr = new PoolingHttpClientConnectionManager();
        // 设置连接池大小
        connMgr.setMaxTotal(100);
        connMgr.setDefaultMaxPerRoute(connMgr.getMaxTotal());

        RequestConfig.Builder configBuilder = RequestConfig.custom();
        // 设置连接超时
        configBuilder.setConnectTimeout(MAX_TIMEOUT);
        // 设置读取超时
        configBuilder.setSocketTimeout(MAX_TIMEOUT);
        // 设置从连接池获取连接实例的超时
        configBuilder.setConnectionRequestTimeout(MAX_TIMEOUT);
        //超时半空闲
        connMgr.setValidateAfterInactivity(30000);
        requestConfig = configBuilder.build();
    }

    /**
     * 发送 get请求
     *
     * @param url
     * @return
     */
    public static JSONObject httpGet(String url, Map<String, String> headerMap) {
        JSONObject jsonResult = null;
        int twoH = 200;
        CloseableHttpClient httpclient = HttpClients.createDefault();
        try {
            url = url.replaceAll(" ", "%20");
            HttpGet httpget = new HttpGet(url);
            if (headerMap != null && !headerMap.isEmpty()) {
                List<String> keyList = new ArrayList<>(headerMap.keySet());
                for (String key : keyList) {
                    httpget.setHeader(key, headerMap.get(key));
                }
            }
            CloseableHttpResponse response = httpclient.execute(httpget);
            /**请求发送成功，并得到响应**/
            if (response.getStatusLine().getStatusCode() == twoH) {
                String strResult = EntityUtils.toString(response.getEntity());
                jsonResult = JSONObject.parseObject(strResult);
            } else {
                log.error("get请求提交失败:{}返回结果 {}" ,url,EntityUtils.toString(response.getEntity()));
            }
        } catch (IOException e) {
            log.error("",e);
        } finally {
            // 关闭连接,释放资源
            try {
                httpclient.close();
            } catch (IOException e) {
                log.error("",e);
            }
        }
        return jsonResult;
    }

    /**
     * post请求
     *
     * @param url       url地址
     * @param jsonParam 参数
     * @return
     */
    public static JSONObject httpPost(String url, JSONObject jsonParam) {
        CloseableHttpClient httpclient = HttpClients.createDefault();
        JSONObject jsonResult = null;
        int twoH = 200;
        HttpPost httppost = new HttpPost(url);
        try {
            if (null != jsonParam) {
                //解决中文乱码问题
                StringEntity entity = new StringEntity(jsonParam.toString(), "utf-8");
                entity.setContentEncoding("UTF-8");
                entity.setContentType("application/json");

                httppost.setEntity(entity);
            }
            CloseableHttpResponse response = httpclient.execute(httppost);
            url = URLDecoder.decode(url, "UTF-8");
            String str = EntityUtils.toString(response.getEntity());
            jsonResult = JSONObject.parseObject(str);
        } catch (IOException e) {
            log.error("post请求提交失败:" + url, e);
        }
        return jsonResult;
    }

    /**
     * post请求
     *
     * @param url    url地址
     * @param params 参数
     * @return
     */
    public static JSONObject httpPost(String url, Map<String, String> params, Map<String, String> headerMap) {
        CloseableHttpClient httpclient = HttpClients.createDefault();
        JSONObject jsonResult = null;
        HttpPost httppost = new HttpPost(url);
        List<NameValuePair> param = new ArrayList<NameValuePair>();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            param.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
        }
        if (headerMap != null && !headerMap.isEmpty()) {
            List<String> keyList = new ArrayList<>(headerMap.keySet());
            for (String key : keyList) {
                httppost.setHeader(key, headerMap.get(key));
            }
        }
        try {
            httppost.setEntity(new UrlEncodedFormEntity(param, "utf-8"));
            CloseableHttpResponse response = httpclient.execute(httppost);
            HttpEntity httpEntity = response.getEntity();
            //取出应答字符串
            String str = EntityUtils.toString(httpEntity);
            jsonResult = JSONObject.parseObject(str);
        } catch (Exception e) {
            log.error("post请求提交失败:" + url, e);
        }
        return jsonResult;
    }


    /**
     * 发送 SSL POST请（HTTPS），K-V形式
     *
     * @param url
     * @param params
     * @author Charlie.chen
     */
    public static String doPostSSL(String url, Map<String, String> params) {
        CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(createSSLConn()).setConnectionManager(connMgr).setDefaultRequestConfig(requestConfig).build();
        HttpPost httpPost = new HttpPost(url);
        CloseableHttpResponse response = null;
        String httpStr = null;

        try {
            httpPost.setConfig(requestConfig);
            List<NameValuePair> pairList = new ArrayList<>(params.size());
            for (Map.Entry<String, String> entry : params.entrySet()) {
                NameValuePair pair = new BasicNameValuePair(entry.getKey(), entry
                        .getValue());
                pairList.add(pair);
            }

            httpPost.setEntity(new UrlEncodedFormEntity(pairList, Charset.forName("utf-8")));
            response = httpClient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            if (entity == null) {
                return null;
            }
            httpStr = EntityUtils.toString(entity, "utf-8");
        } catch (Exception e) {
            log.error("",e);
        } finally {
            if (response != null) {
                try {
                    EntityUtils.consume(response.getEntity());
                } catch (IOException e) {
                    log.error("",e);
                }
            }
        }
        return httpStr;
    }


    /**
     * 创建SSL安全连接
     *
     * @return
     * @author Charlie.chen
     */
    private static SSLConnectionSocketFactory createSSLConn() {
        SSLConnectionSocketFactory sslsf = null;
        try {
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (TrustStrategy) (chain, authType) -> true).build();

            sslsf = new SSLConnectionSocketFactory(sslContext, (arg0, arg1) -> true);
        } catch (GeneralSecurityException e) {
            log.error("",e);
        }
        return sslsf;
    }
}
